package iagovsothello.core;

import java.util.*;

public class GameState implements java.io.Serializable {

	private static final long serialVersionUID = -3129569544555376764L;

	/*
	 * 0: posizione vuota
	 * 1: pedina giocatore 1
	 * 2: pedina giocatore 2
	*/
	private int[][] table;
	
	private int currentPlayer;
	private int otherPlayer;
	private int dimension;
	private int turnNumber;
	
	/*
	 * Ultima mossa inserita
	 */
	private Position lastMove;
	
	/*
	 * 0: gioco normale
	 * 1: è stato incontrato uno stato in cui il giocatore corrente non ha mosse legali
	 * 2: game over (anche il secondo giocatore non ha mosse legali)
	 */
	private int gameState;
	
	public GameState(int dimension, int currentPlayer)
	{
		this.dimension = dimension;
		table = new int[dimension][dimension];
		this.currentPlayer = currentPlayer;
		this.gameState = 0;
		this.lastMove = null;
		if (currentPlayer == 1)
			otherPlayer = 2;
		else
			otherPlayer = 1;
		turnNumber = 1;
	}
	
	public GameState(GameState parent)
	{
		this.dimension = parent.dimension;
		this.table = new int[dimension][dimension];
		for (int i = 0; i < dimension; i++)
		{
			for (int j = 0; j < dimension; j++)
			{
				table[i][j] = parent.table[i][j];
			}
		}
		this.lastMove = parent.lastMove;
		this.gameState = parent.gameState;
		this.currentPlayer = parent.currentPlayer;
		this.otherPlayer = parent.otherPlayer;
		this.turnNumber = parent.turnNumber;
	}
	
	public static GameState createStartingState(int dimension)
	{
		GameState startingState = new GameState(dimension,2);
		startingState.setSquareStatus(dimension/2-1,dimension/2-1,1);
		startingState.setSquareStatus(dimension/2,dimension/2,1);
		startingState.setSquareStatus(dimension/2,dimension/2-1,2);
		startingState.setSquareStatus(dimension/2-1,dimension/2,2);
		return startingState;
	}
	
	public GameState clone()
	{
		return new GameState(this);
	}
	
	public int getCurrentPlayer() 
	{
		return currentPlayer;
	}

	public void setCurrentPlayer(int currentPlayer) 
	{
		this.currentPlayer = currentPlayer;
		if (currentPlayer == 1)
			otherPlayer = 2;
		else
			otherPlayer = 1;
	}

	public int getOtherPlayer() 
	{
		return otherPlayer;
	}

	public boolean isMyTurn(int playerNumber)
	{
		return (playerNumber == currentPlayer);
	}
	
	public void switchTurn()
	{
		int temp = currentPlayer;
		currentPlayer = otherPlayer;
		otherPlayer = temp;
	}
	
	public int getDimension() 
	{
		return dimension;
	}

	public int getSquareStatus(int x, int y)
	{
		return table[y][x];
	}
	
	public void setSquareStatus(int x, int y, int status)
	{
		table[y][x] = status;
	}
	
	public int getTurnNumber()
	{
		return turnNumber;
	}

	/**
	 * Oggetto di tipo <code>Position</code> che rappresenta l'ultima mossa che è stata inserita per effetto di una chiamata del metodo <code>move</code>.
	 * @return ultima posizione inserita nel gioco; può restituire <code>null</code> se non è stata inserita alcuna mossa oppure se l'ultima mossa inserita era proprio <code>null</code>
	 */
	public Position getLastMove()
	{
		return lastMove;
	}
	
	/**
	 * Metodo che riceve una mossa (Position p) e crea un nuovo oggetto GameState che rappresenta la othelliera modificata dalla mossa p
	 * @param p
	 * @return
	 * @throws OthelloException
	 */
	public GameState cloneAndMove(Position p) throws OthelloException
	{
		GameState copy = clone();
		copy.move(p);
		return copy;
	}
	/*
	public GameState cloneAndMove(Move m) throws OthelloException{
		
		GameState copy = clone();
		copy.move(m.position);
		return copy;
	}
*/
	
	/**
	 * Metodo che riceve una mossa in ingresso e modifica la tabella di conseguenza secondo le regole dell'Othello
	 * @param p
	 * @return
	 * @throws OthelloException
	 */
	public List<Position> move(Position p) throws OthelloException
	{
		if (p == null && ((gameState == 0 && hasLegalPositions()) || gameState == 2))
			throw new OthelloException("Something awful has happened - gameState: "+gameState);
		
		//verifica che la posizione nella quale si vuole inserire la pedina sia libera
		if (p != null && (table[p.y][p.x] != 0))
			throw new OthelloException("Position is not empty");
		
		//lista che conterrˆ tutte le pedine che CAMBIERANNO DI COLORE in seguito alla mossa p
		List<Position> markedPositions = new LinkedList<Position>();
		
		if (p != null)
		{
			List<Position> tempPositions = new LinkedList<Position>();
			//considerata una pedina, verifico in tutte le 8 possibili "direzioni" il colore delle altre pedine presenti sulla scacchiera
			//
			//			   0 1 2	
			//			   3 X 4
			//			   5 6 7
			int direction = 0;
			int tx, ty, xStep, yStep, opponentPieces;
			while (direction < 8)
			{
				//inserisco gli incrementi di posizione relativi alla posizione che sto percorrendo
				xStep = getXStep(direction);
				yStep = getYStep(direction);
				//tx e ty rappresentano la posizione attuale che sto esaminando
				tx = p.x +xStep;
				ty = p.y +yStep;
				//opponetPieces rappresenta quante pedine avversarie vengono incontrate nella direzione scelta
				opponentPieces = 0;
				
				//se la posizione esaminata � una posizione interna alla tabella ed � occupata da una pedina avversaria,
				//questa posizione viene salvata all'interno della lista markedPosition.
				while(tx >= 0 && tx < dimension && ty >= 0 && ty < dimension && table[ty][tx] == otherPlayer)
				{
					tempPositions.add(new Position(tx,ty));
					tx += xStep;
					ty += yStep;
					opponentPieces++;
				}
				//se la posizione esaminata � una posizione interna alla tabella ed � occupata da una pedina alleata e se precedentemente �
				//stata incontrata una o pi� pedine avversarie nella stessa direzione, allora tutte le pedine avversarie dovranno essere 
				//modificate in pedine alleate
				if (tx >= 0 && tx < dimension && ty >= 0 && ty < dimension && opponentPieces > 0 && table[ty][tx] == currentPlayer)
					markedPositions.addAll(tempPositions);
				tempPositions.clear();
				direction++;
			}
			
			if (markedPositions.isEmpty())
				throw new OthelloException("Rule violation in "+ p +" for player "+currentPlayer+"\n"+this.toGridString());
			
			//se è tutto a posto, si aggiorna lo stato del gioco mettendo la pedina in posizione e cambiando il colore alle pedine influenzate; si aggiorna anche l'attributo lastMove
			table[p.y][p.x] = currentPlayer;
			
			for (Position mp : markedPositions)
			{
				table[mp.y][mp.x] = currentPlayer;
			}
			
		}
		
		//se p=null con gameState = 1 vuol dire che il primo giocatore non aveva mosse legali da effettuare e passa il turno all'altro.
		else if (gameState == 1)
			gameState = 2;
		
		lastMove = p;
		turnNumber++;
		switchTurn();
		return markedPositions;
	}
	
	/**
	 * Verifica se la posizione inserita rispetta le regole dell'Othello
	 */
	public boolean isPositionLegal(Position p)
	{
		return isPositionLegal(p.x, p.y, currentPlayer, otherPlayer);
	}
	
	/**
	 * Verifica se la posizione inserita rispetta le regole dell'Othello
	 * @param x
	 * @param y
	 * @param player
	 * @param opponent
	 * @return
	 */
	public boolean isPositionLegal(int x, int y, int player, int opponent)
	{
		if (table[y][x] == 0)
		{
			boolean legal = false;
			int direction = 0;
			int tx, ty, xStep, yStep, opponentPieces;
			while (direction < 8 && !legal)
			{
				xStep = getXStep(direction);
				yStep = getYStep(direction);
				tx = x +xStep;
				ty = y +yStep;
				opponentPieces = 0;
				
				while(tx >= 0 && tx < dimension && ty >= 0 && ty < dimension && table[ty][tx] == opponent)
				{
					tx += xStep;
					ty += yStep;
					opponentPieces++;
				}
				if (tx >= 0 && tx < dimension && ty >= 0 && ty < dimension && opponentPieces > 0 && table[ty][tx] == player)
					legal = true;
				direction++;
			}
			return legal;
		}
		else
			return false;
	}
	
	public List<Move> getLegalMoves()
	{
		List<Move> list = new LinkedList<Move>();
		for (int i = 0; i < dimension; i++)
		{
			for (int j = 0; j < dimension; j++)
			{
				if (table[i][j] != currentPlayer && table[i][j] != otherPlayer)
				{
					int tx, ty, xStep, yStep, opponentPieces;
					int totalPieces = 0;
					for (int direction = 0; direction < 8; direction++)
					{
						xStep = getXStep(direction);
						yStep = getYStep(direction);
						tx = j +xStep;
						ty = i +yStep;
						opponentPieces = 0;
						
						while(tx >= 0 && tx < dimension && ty >= 0 && ty < dimension && table[ty][tx] == otherPlayer)
						{
							tx += xStep;
							ty += yStep;
							opponentPieces++;
						}
						if (tx >= 0 && tx < dimension && ty >= 0 && ty < dimension && opponentPieces > 0 && table[ty][tx] == currentPlayer)
						{
							totalPieces += opponentPieces;
						}
					}
					if (totalPieces > 0)
					{
						/*totalPieces+1 perchè nella variazione del punteggio totale conta anche la pedina che è 
						 * stata inserita, oltre quelle che vengono girate*/
						list.add(new Move(new Position(j,i),totalPieces+1));
					}
				}
			}
		}
		if (list.isEmpty())
		{
			if (gameState == 0)
				gameState = 1;
		}
		else if (gameState != 0)
			gameState = 0;
		
		return list;
	}
	/**
	 * Verifica se la tabella nello stato attuale possiede ALMENO una posizione legale
	 * @return
	 */
	public boolean hasLegalPositions()
	{
		return (!getLegalPositions(currentPlayer, otherPlayer).isEmpty());
	}
	/**
	 * Restituisce la lista delle posizioni legali
	 * @return
	 */
	public List<Position> getLegalPositions()
	{
		return getLegalPositions(currentPlayer, otherPlayer);
	}
	/**
	 * Restituisce la lista delle posizioni legali
	 * @return
	 */
	public List<Position> getLegalPositions(int player, int opponent)
	{
		List<Position> list = new LinkedList<Position>();
		for (int i = 0; i < dimension; i++)
		{
			for (int j = 0; j < dimension; j++)
			{
				if (isPositionLegal(j,i,player,opponent))
					list.add(new Position(j,i));
			}
		}
		//se la lista di posizioni legali � vuota, allora se lo stato della partita � 0 (gioco normale) deve andare nello stato 1 (stallo del primo giocatore)
		//se la lista di posizioni legali non � vuota e se lo stato della partita � diverso da 0 (gioco normale), lo stato ritorna a essere 0
		if (list.isEmpty())
		{
			if (gameState == 0)
				gameState = 1;
		}
		else if (gameState != 0)
			gameState = 0;
		
		return list;
	}
	
	/**
	 * Metodo che verifica se la configurazione delle pedine rappresenta un'apertura perpendicolare. L'utilizzo di questo metodo ha senso solo se il
	 * turno corrente è 3 (ossia non appena il giocatore bianco ha effettuato l'apertura), perchè in tutti gli altri casi restituirebbe valori privi di senso, dato 
	 * che questo metodo verifica esplicitamente se alcune posizioni sono occupate o meno da certe pedine.
	 * @return <code>true</code> se la configurazione rappresenta un'apertura perpendicolare, <code>false</code> altrimenti
	 */
	public boolean perpendicularOpening()
	{
		return ((table[dimension/2-2][dimension/2-1] == 2 && table[dimension/2-1][dimension/2-1] == 2 && table[dimension/2-1][dimension/2] == 2) ||
				(table[dimension/2-1][dimension/2-2] == 2 && table[dimension/2-1][dimension/2-1] == 2 && table[dimension/2][dimension/2-1] == 2) ||
				(table[dimension/2-1][dimension/2] == 2 && table[dimension/2][dimension/2] == 2 && table[dimension/2][dimension/2+1] == 2) ||
				(table[dimension/2][dimension/2-1] == 2 && table[dimension/2][dimension/2] == 2 && table[dimension/2+1][dimension/2] == 2));
	}
	
	/**
	 * Metodo che verifica se la configurazione delle pedine rappresenta un'apertura diagonale. L'utilizzo di questo metodo ha senso solo se il
	 * turno corrente è 3 (ossia non appena il giocatore bianco ha effettuato l'apertura), perchè in tutti gli altri casi restituirebbe valori privi di senso, dato 
	 * che questo metodo verifica esplicitamente se alcune posizioni sono occupate o meno da certe pedine.
	 * @return <code>true</code> se la configurazione rappresenta un'apertura diagonale, <code>false</code> altrimenti
	 */
	public boolean diagonalOpening()
	{
		return ((table[dimension/2-2][dimension/2-2] == 1 && table[dimension/2-1][dimension/2-1] == 1 && table[dimension/2][dimension/2] == 1) ||
				(table[dimension/2+1][dimension/2+1] == 1 && table[dimension/2-1][dimension/2-1] == 1 && table[dimension/2][dimension/2] == 1));
	}
	
	/**
	 * Metodo che verifica se la configurazione delle pedine rappresenta un'apertura parallela. L'utilizzo di questo metodo ha senso solo se il
	 * turno corrente è 3 (ossia non appena il giocatore bianco ha effettuato l'apertura), perchè in tutti gli altri casi restituirebbe valori privi di senso, dato 
	 * che questo metodo verifica esplicitamente se alcune posizioni sono occupate o meno da certe pedine.
	 * @return <code>true</code> se la configurazione rappresenta un'apertura parallela, <code>false</code> altrimenti
	 */
	public boolean parallelOpening()
	{
		return ((table[dimension/2-2][dimension/2-1] == 2 && table[dimension/2-1][dimension/2-1] == 2 && table[dimension/2][dimension/2-1] == 2) ||
				(table[dimension/2-1][dimension/2-2] == 2 && table[dimension/2-1][dimension/2-1] == 2 && table[dimension/2-1][dimension/2] == 2) ||
				(table[dimension/2][dimension/2-1] == 2 && table[dimension/2][dimension/2] == 2 && table[dimension/2][dimension/2+1] == 2) ||
				(table[dimension/2-1][dimension/2] == 2 && table[dimension/2][dimension/2] == 2 && table[dimension/2+1][dimension/2] == 2));
	}
	
	/**
	 * Calcola la mobilità per il giocatore attuale
	 * @return un intero che rappresenta il numero di mosse che può eseguire il giocatore attuale
	 */
	public int mobility(int player)
	{
		List<Position> list = getLegalPositions(player, getOpponent(player));
		return list.size();
	}
	
	/**
	 * Calcola la mobilità potenziale per il giocatore corrente.
	 * @return numero totale di caselle vuote adiacenti ad almeno una pedina appartenente al giocatore corrente
	 */
	public int potentialMobility()
	{
		return potentialMobility(currentPlayer);
	}
	
	/**
	 * Calcola la mobilità potenziale per un giocatore.
	 * @param player giocatore del quale calcolare la mobilità potenziale
	 * @return numero totale di caselle vuote adiacenti ad almeno una pedina appartenente al giocatore specificato
	 */
	public int potentialMobility(int player)
	{
		int mobility = 0;
		for (int i = 0; i < dimension; i++)
		{
			for (int j = 0; j < dimension; j++)
			{
				if (table[i][j] == 0)
				{
					int direction = 0;
					boolean found = false;
					int tx,ty;
					while (direction < 8 && !found)
					{
						tx = j+getXStep(direction);
						ty = i+getYStep(direction);
						if (tx >= 0 && tx < dimension && ty >= 0 && ty < dimension && table[ty][tx] == player)
						{
							found = true;
							mobility++;
						}
						direction++;
					}
				}
			}
		}
		return mobility;
	}
	
	/**
	 * Verifica se la partita � finita
	 * @return
	 */
	public boolean isGameOver()
	{
		return (gameState == 2 && !hasLegalPositions());
	}
	
	/**
	 * Restitiuisce il giocatore che al momento ha un punteggio più alto (se la partita � finita restiuisce il giocatore vincente)
	 * @return 1 se il giocatore 1 ha più punti del giocatore 2, 2 nel caso opposto, 0 se i due giocatori sono in pareggio
	 */
	public int getVictor()
	{
		int dimension = table.length;
		int points1 = 0;
		int points2 = 0;
		for (int i = 0; i < dimension; i++)
		{
			for (int j = 0; j < dimension; j++)
			{
				if (table[i][j] == 1)
					points1++;
				else if (table[i][j] == 2)
					points2++;
			}
		}
		if (points1 > points2)
			return 1;
		else if (points1 < points2)
			return 2;
		else
			return 0;
	}
	/**
	 * Verifica che i punteggi dei due giocatori sono uguali (se la partita � finita allora � un pareggio)
	 * @return
	 */
	public boolean isDraw()
	{
		int dimension = table.length;
		int points1 = 0;
		int points2 = 0;
		for (int i = 0; i < dimension; i++)
		{
			for (int j = 0; j < dimension; j++)
			{
				if (table[i][j] == 1)
					points1++;
				else if (table[i][j] == 2)
					points2++;
			}
		}
		return (points1 == points2);
	}
	
	public int getPoints(int player)
	{
		int dimension = table.length;
		int points = 0;
		for (int i = 0; i < dimension; i++)
		{
			for (int j = 0; j < dimension; j++)
			{
				if (table[i][j] == player)
					points++;
			}
		}
		return points;
	}
	
	public String toString()
	{
		String s = "";
		for (int i = 0; i < dimension; i++)
		{
			for (int j = 0; j < dimension; j++)
			{
				s = s + table[i][j];
			}
		}
		s = s + "-" + currentPlayer;
		return s;
	}
	
	public String toGridString()
	{
		String s = "";
		for (int i = 0; i < dimension; i++)
		{
			for (int j = 0; j < dimension; j++)
			{
				s = s + " " + table[i][j];
			}
			s = s + "\n";
		}
		return s;
	}
	/**
	 * Resitiuisce l'incremento lungo l'asse X per spostarsi lungo una direzione
	 * @param direction
	 * @return
	 */
	private int getXStep(int direction)
	{
		if (direction == 0 || direction == 3 || direction == 5)
			return -1;
		else if (direction == 1 || direction == 6)
			return 0;
		else 
			return 1;
	}
	/**
	 * Resitiuisce l'incremento lungo l'asse Y per spostarsi lungo una direzione
	 * @param direction
	 * @return
	 */
	private int getYStep(int direction)
	{
		if (direction <= 2)
			return -1;
		else if (direction <= 4)
			return 0;
		else
			return 1;
	}
	/**
	 * Metodo che resitiuisce una TreeMap che contiene le posizioni degli angoli e i loro valori (angolo vuoto,pedina nera o pedina bianca)
	 * @return
	 */
public Map<Position,Integer> getCorners(){
		
		
		TreeMap <Position, Integer> corners = new TreeMap<Position, Integer>();
	//	int corners[] = new int[4];
				
		corners.put(new Position(0,0), table[0][0]);
		corners.put(new Position(0,dimension-1), table[0][dimension-1]);
		corners.put(new Position(dimension-1,0), table[dimension-1][0]);
		corners.put(new Position(dimension-1,dimension-1), table[dimension-1][dimension-1]);

		

		return corners;
		
		
	}
	/*public Map<Position,Integer> getCorners(){
		
		
		TreeMap <Position, Integer> corners = new TreeMap<Position, Integer>();
	//	int corners[] = new int[4];
				
		corners.put(new Position(0,0), table[0][0]);
		corners.put(new Position(0,dimension-1), table[0][dimension-1]);
		corners.put(new Position(dimension-1,0), table[dimension-1][0]);
		corners.put(new Position(dimension-1,dimension-1), table[dimension-1][dimension-1]);

		

		return corners;
		
		
	}*/
	/**
	 * Restituisce un array che contiene informazioni su QUANTE pedine si trovano nelle caselle adiacenti a quella passata nel parametro d'ingresso Position p.
	 *  v[0] -> numero posizioni VUOTE
	 *  v[1] -> numero posizioni GIOCATORE BIANCO
	 *  v[2] -> numero posizioni GIOCATORE NERO
	 * @param p
	 * @return
	 */
	public int[] getAdjacent(Position p){
		
		
		int v[] = new int[3];
		
		int direction = 0;
		int tx, ty = 0;
		
		while (direction < 8 )
		{
			tx = p.x + getXStep(direction);
			ty = p.y +getYStep(direction);
			if (tx >= 0 && tx < dimension && ty >= 0 && ty < dimension )
					v[table[ty][tx]]++;	
			direction++;
		}
			
			
		return v;
		/*
		TreeMap <Position, Integer> adjacent = new TreeMap<Position, Integer>();
		int direction = 0;
		int tx, ty = 0;
		
		while (direction < 8 )
		{
			tx = p.x + getXStep(direction);
			ty = p.y +getYStep(direction);
			if (tx >= 0 && tx < dimension && ty >= 0 && ty < dimension ){
				adjacent.put(new Position(tx,ty), table[ty][tx]);

			}
					
			direction++;
		}
		return adjacent;
		*/
	}
	public static int getOpponent(int player){
		
		if(player == 1)
			return 2;
		else if(player == 2)
			return 1;
		else
			return 0;
	}
	/**
	 * Restituisce un array che contiene informazioni su QUANTE pedine si trovano nelle caselle dei bordi del tabellone.
	 *  v[0] -> numero posizioni VUOTE
	 *  v[1] -> numero posizioni GIOCATORE BIANCO
	 *  v[2] -> numero posizioni GIOCATORE NERO
	 * @return
	 */
	public int[] getEdge(){
		
		int v[] = new int[3];
		for(int i =0; i < dimension;i++){
			v[table[0][i]]++;
		}
		for(int i =0; i < dimension;i++){
			v[table[dimension-1][i]]++;
		}
		for(int i =0; i < dimension;i++){
			v[table[i][0]]++;
		}
		for(int i =0; i < dimension;i++){
			v[table[i][dimension-1]]++;
		}
		
		return v;
	}

	public int edgeStability(int player){
	
		int stability = 0;
		
		// mi prendo gli angoli
		Map <Position, Integer> corners = getCorners();
		int vCorners[] = new int [4];
		
		Position posCornerA = new Position(0,0);
		Position posCornerB = new Position(0,dimension-1);
		Position posCornerC = new Position(dimension-1,0);
		Position posCornerD = new Position(dimension-1,dimension-1);

		vCorners[0] = corners.get(posCornerA);
		vCorners[1] = corners.get(posCornerB);
		vCorners[2] = corners.get(posCornerC);
		vCorners[3] = corners.get(posCornerD);
		
		for(int i = 0; i < vCorners.length;i++){
			if(vCorners[i] == player)
				stability++;
		}
		
		//lato A<--->B
		int[] vEdgeAB = new int [dimension-2];
		
		for(int i = 0; i < vEdgeAB.length;i++){
			vEdgeAB[i] = table[0][i+1];
		}
		
		//nell'angolo A c'è una pedina stabile, in B no
		if((vCorners[0] == player) && (vCorners[1] != player)){
			boolean end = false;
			int i = 0;
			while(!end && i < vEdgeAB.length){
				
				if(vEdgeAB[i] == player){
					stability++;
					i++;
				}
				else
					end = true;
			}
		}
		
		//nell'angolo B c'è una pedina stabile, in A no
		else if((vCorners[0] != player) && (vCorners[1] == player)){
			boolean end = false;
			//guardo le pedine da B verso A
			int i = vEdgeAB.length-1;
			while(!end && i >= 0){
				
				if(vEdgeAB[i] == player){
					stability++;
					i--;
				}
				else
					end = true;
			}
		}
		
		//sia in A che in B ci sono pedine stabili
		else if((vCorners[0] == player) && (vCorners[1] == player)){
			
			boolean end = false;
			int i = 0;
			while(!end && i < vEdgeAB.length){
				
				if(vEdgeAB[i] == player){
					stability++;
					i++;
				}
				else{
					int j = vEdgeAB.length-1;
					while(!end && j >= 0){
						
						if(vEdgeAB[j] == player){
							stability++;
							j--;
						}
						else
							end = true;
					}
				}
					
			}
		}

		//lato A<--->C
		int[] vEdgeAC = new int [dimension-2];
		
		for(int i = 0; i < vEdgeAC.length;i++){
			vEdgeAC[i] = table[i+1][0];
		}
		
		//nell'angolo A c'è una pedina stabile, in C no
		if((vCorners[0] == player) && (vCorners[2] != player)){
			boolean end = false;
			int i = 0;
			while(!end && i < vEdgeAC.length){
				
				if(vEdgeAC[i] == player){
					stability++;
					i++;
				}
				else
					end = true;
			}
		}
		
		//nell'angolo C c'è una pedina stabile, in A no
		else if((vCorners[0] != player) && (vCorners[2] == player)){
			boolean end = false;
			//guardo le pedine da B verso A
			int i = vEdgeAC.length-1;
			while(!end && i >= 0){
				
				if(vEdgeAC[i] == player){
					stability++;
					i--;
				}
				else
					end = true;
			}
		}
		
		//sia in A che in C ci sono pedine stabili
		else if((vCorners[0] == player) && (vCorners[2] == player)){
			
			boolean end = false;
			int i = 0;
			while(!end && i < vEdgeAC.length){
				
				if(vEdgeAC[i] == player){
					stability++;
					i++;
				}
				else{
					int j = vEdgeAC.length-1;
					while(!end && j >= 0){
						
						if(vEdgeAC[j] == player){
							stability++;
							j--;
						}
						else
							end = true;
					}
				}
					
			}
		}

		//lato B<--->D
		int[] vEdgeBD = new int [dimension-2];
		
		for(int i = 0; i < vEdgeBD.length;i++){
			vEdgeBD[i] = table[i+1][dimension-1];
		}
		
		//nell'angolo B c'è una pedina stabile, in D no
		if((vCorners[1] == player) && (vCorners[3] != player)){
			boolean end = false;
			int i = 0;
			while(!end && i < vEdgeBD.length){
				
				if(vEdgeBD[i] == player){
					stability++;
					i++;
				}
				else
					end = true;
			}
		}
		
		//nell'angolo D c'è una pedina stabile, in B no
		else if((vCorners[1] != player) && (vCorners[3] == player)){
			boolean end = false;
			//guardo le pedine da B verso A
			int i = vEdgeBD.length-1;
			while(!end && i >= 0){
				
				if(vEdgeBD[i] == player){
					stability++;
					i--;
				}
				else
					end = true;
			}
		}
		
		//sia in B che in D ci sono pedine stabili
		else if((vCorners[1] == player) && (vCorners[3] == player)){
			
			boolean end = false;
			int i = 0;
			while(!end && i < vEdgeBD.length){
				
				if(vEdgeBD[i] == player){
					stability++;
					i++;
				}
				else{
					int j = vEdgeBD.length-1;
					while(!end && j >= 0){
						
						if(vEdgeBD[j] == player){
							stability++;
							j--;
						}
						else
							end = true;
					}
				}
					
			}
		}

		//lato C<--->D
		int[] vEdgeCD = new int [dimension-2];
		
		for(int i = 0; i < vEdgeCD.length;i++){
			vEdgeCD[i] = table[dimension-1][i+1];
		}
		
		//nell'angolo C c'è una pedina stabile, in D no
		if((vCorners[2] == player) && (vCorners[3] != player)){
			boolean end = false;
			int i = 0;
			while(!end && i < vEdgeCD.length){
				
				if(vEdgeCD[i] == player){
					stability++;
					i++;
				}
				else
					end = true;
			}
		}
		
		//nell'angolo D c'è una pedina stabile, in C no
		else if((vCorners[2] != player) && (vCorners[3] == player)){
			boolean end = false;
			//guardo le pedine da B verso A
			int i = vEdgeCD.length-1;
			while(!end && i >= 0){
				
				if(vEdgeCD[i] == player){
					stability++;
					i--;
				}
				else
					end = true;
			}
		}
		
		//sia in C che in D ci sono pedine stabili
		else if((vCorners[2] == player) && (vCorners[3] == player)){
			
			boolean end = false;
			int i = 0;
			while(!end && i < vEdgeCD.length){
				
				if(vEdgeCD[i] == player){
					stability++;
					i++;
				}
				else{
					int j = vEdgeCD.length-1;
					while(!end && j >= 0){
						
						if(vEdgeCD[j] == player){
							stability++;
							j--;
						}
						else
							end = true;
					}
				}
					
			}
		}
		

		return stability;
	}	
}
